package com.yehun.web.controller;


import com.yehun.entity.ResultEntity;
import com.yehun.enums.ResultEnum;
import com.yehun.exception.CustomException;
import com.yehun.exception.ErrorException;
import com.yehun.shiro.ShiroUser;
import com.yehun.utils.ExceptionUtils;
import com.yehun.utils.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.ServletRequestDataBinder;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.UndeclaredThrowableException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class BaseController {

    private final static Logger logger = LoggerFactory.getLogger(BaseController.class);

    @InitBinder
    protected void initialize(HttpServletRequest request, ServletRequestDataBinder binder) {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        dateFormat.setLenient(false);
        binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
    }


    /**
     * 获取请求属性封装为Map类型
     */
    Map<String, Object> getRequestMap(HttpServletRequest request) {
        Map<String, Object> conditions = new HashMap<>();
        Map map = request.getParameterMap();
        for (Object o : map.keySet()) {
            String key = (String) o;
            conditions.put(key, ((String[]) map.get(key))[0]);
        }
        return conditions;
    }


    /**
     * 获取当前登录用户对象
     */
    public ShiroUser getCurrentUser() {
        Subject subject = SecurityUtils.getSubject();
        return subject != null ? (ShiroUser) subject.getPrincipal() : null;
    }


    /**
     * 自定义异常捕捉
     */
    @ExceptionHandler(value = CustomException.class)
    public ModelAndView customException(Exception ex) throws IOException {
        String errorMessage = ExceptionUtils.getExceptionAllinformation(ex);
        logger.error(errorMessage);
        ModelAndView view = new ModelAndView("error");
        ResultEntity result = new ResultEntity();
        if(ex instanceof CustomException) {
            ResultEnum resultEnum = ((CustomException) ex).getCode();
            result.setResult(resultEnum);
            result.setMessage(StringUtils.isEmpty(ex.getMessage()) ? resultEnum.getText() : ex.getMessage());
        } else {
            result.setResult((ResultEnum.Expertion));
            result.setMessage(ex.getMessage());
        }
        view.addObject("result", result);
        return view;
    }

    /**
     * 全局异常捕捉
     */
    @ExceptionHandler(value = Exception.class)
    public ModelAndView globalException(HttpServletResponse response, Exception ex) {
        response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
        response.setCharacterEncoding("UTF-8");
        String errorMessage;
        ModelAndView view = new ModelAndView("error");
        ResultEntity result = new ResultEntity();
        if(ex instanceof UndeclaredThrowableException) { //annotation抛出的异常, 需单独处理
            ErrorException exception = (ErrorException) ((UndeclaredThrowableException)ex).getUndeclaredThrowable();
            errorMessage = ExceptionUtils.getExceptionAllinformation(exception);
            result.setResult(exception.getCode());
            result.setMessage(exception.getMessage());
        } else if (ex instanceof MethodArgumentTypeMismatchException) {
            MethodArgumentTypeMismatchException exception = (MethodArgumentTypeMismatchException) ex;
            errorMessage = ExceptionUtils.getExceptionAllinformation(exception);
            result.setResult(ResultEnum.MethodTypeError);
        } else {
            errorMessage = ExceptionUtils.getExceptionAllinformation(ex);
            result.setResult(ResultEnum.Expertion);
            result.setMessage(ex.getMessage());
        }
        logger.error(errorMessage);
        view.addObject("result", result);
        return view;
    }


}
